package com.ctsi.auth.integration;

import com.ctsi.auth.vcc.manager.VerificationCodeService;
import com.ctsi.commons.util.UtilValidate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.util.Base64Utils;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author zhangjw
 * @className ImageResourceOwnerPasswordTokenGranter
 * @description 基于验证码的验证策略
 * @date 2019/2/26 15:24
 **/
public class ImageResourceOwnerPasswordTokenGranter extends ResourceOwnerPasswordTokenGranter {
    private static final Logger logger = LoggerFactory.getLogger(ImageResourceOwnerPasswordTokenGranter.class);

    private static final String VC_TYPE = "image";
    private static final String IGNORE_VC_TYPE = "app";
    private final byte[] PRIVATE_KEY;
    /**
     * 自定义验证方式
     */
//    private static final String GRANT_TYPE = "customPWD";
    private static final String PRIVATE_KEY_STR = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJvS9/qGrvZ7gVLBF4c5c/bKxzpG0BGm8xO2onkcGNTbFdWkOBga36zACHgE4pvus7rctrNYqqCGkOZQjqxxnAuw4iLAQa75fQQ6n95k+gwULbwYgD7ldszFpKqTsPKcPNwTRjMsVyjSnQhwVQScNVbwuu/gA1GoxXU+CM/jXNK/AgMBAAECgYAbIGn9Gg9BZ5TG5EiFSPIwJ3LxaTx1pjuw1d2I+eQ0wgMWEyWUxLDlsPSIeEk+3ho50IyZwjjKA0McZS/BQ3HnrVUSlJdflwG8/L9C0VD5mfqohpE/f96w5KbzF1OIGs2xXztHK5+nyoM3yDPJN0zKmMs0qg/P+zqgEmkix2ikSQJBANlCgt3HqIfsTIRub5LwiQcgu3/JRXXk9LtZXqqgnHpUWUcZ1CHPbi/jNsxJ9PZY4dfSQDkFzBXAZnC42h5/QvMCQQC3nAlO1TX7a2zS4uK/MYs99fJdknctmLFkvzgdD+aEJfGCrELiE97B+31Uh/dpl2Ttsmt0t7FCz6uImemvVmwFAkEAltNmuIKYTCxOfo2QZakY59rgb/kRgKP/BmUnpDq2BvKxu/uBWit/6jzJ2Q7qwW648rRio3OT1/Hm7BBYVF2y4wJAaznr0acANIkC75FivCdx2siENxMvGGjAyEZHvekoROpnxVlWYfMatwxon/IbkgXBAnOc/3e7RHpFAaxo5WXCBQJADW4bqGGKoeGvewP7cRRNLx6VJ+d7U9xjovjeS84MUO6FzvKj3RL/8zGHPqfKuoiw/oCz09oiqjHTnAEJmY1HDg==";

    private AuthenticationManager authenticationManager;
    private VerificationCodeService verificationCodeService;

    public ImageResourceOwnerPasswordTokenGranter(AuthenticationManager authenticationManager,
                                                  AuthorizationServerTokenServices tokenServices,
                                                  ClientDetailsService clientDetailsService,
                                                  OAuth2RequestFactory requestFactory,
                                                  VerificationCodeService verificationCodeService) {
//        super(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
        super(authenticationManager, tokenServices, clientDetailsService, requestFactory);
        this.authenticationManager = authenticationManager;
        this.verificationCodeService = verificationCodeService;
        this.PRIVATE_KEY = Base64Utils.decodeFromString(PRIVATE_KEY_STR);
    }

    /**
     * 加入验证码验证
     * @param client
     * @param tokenRequest
     * @return
     */
    @Override
    protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
        Map<String, String> parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters());
        String vc_token = parameters.get("vc_token");
        String vc_code = parameters.get("vc_code");
        String vc_type = parameters.get("auth_type");
        String username = parameters.get("username");
        String password = parameters.get("password");
        logger.error("收到密文： {}",password);
        // Protect from downstream leaks of password
        parameters.remove("password");
        /**
         * 校验验证码
         */
        if (UtilValidate.isEmpty(vc_type)) {
            throw new InvalidGrantException("校验类型不能为空!");
        }
        if (VC_TYPE.equalsIgnoreCase(vc_type)) {
            boolean result = verificationCodeService.validate(vc_token,vc_code,null);
            /**
             * 验证码有效期内只能使用一次
             */
            verificationCodeService.evictCache(vc_token,null);
            if (!result) {
                throw new InvalidGrantException("验证码错误!");
            }
            /**
             * 解密前台传入的密码 RSA
             */
            try {
                byte[] pwd = Base64Utils.decodeFromString(password);
                password =  new String(RSAUtil.decryptByPrivateKey(pwd,PRIVATE_KEY));
                logger.warn("解密密码：{}",password);
            } catch (Exception e) {
                logger.error("decrypt password error: {}",e);
                throw new RuntimeException("密码解码错误!");
            }
        } else if (IGNORE_VC_TYPE.equalsIgnoreCase(vc_type)) {
            // do nothing ......
        } else {
            throw new InvalidGrantException("校验类型不能为空!");
        }
        Authentication userAuth = new UsernamePasswordAuthenticationToken(username, password);
        ((AbstractAuthenticationToken) userAuth).setDetails(parameters);
        try {
            userAuth = authenticationManager.authenticate(userAuth);
        }
        catch (AccountStatusException ase) {
            //covers expired, locked, disabled cases (mentioned in section 5.2, draft 31)
            throw new InvalidGrantException(ase.getMessage());
        }
        catch (BadCredentialsException e) {
            // If the username/password are wrong the spec says we should send 400/invalid grant
            throw new InvalidGrantException(e.getMessage());
        }
        if (userAuth == null || !userAuth.isAuthenticated()) {
            throw new InvalidGrantException("Could not authenticate user: " + username);
        }

        OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
        return new OAuth2Authentication(storedOAuth2Request, userAuth);
    }
}
